/**
 * @file    gt98xx_drv_i2c.c
 * @author  Giantec-Semi ATE
 * @brief   Source file of SPI driver module.
 * @version 0.1
 * 
 * @copyright Copyright (c) 2021 Giantec-Semi
 */

#include "gt98xx_drv_i2c.h"

/**
 * @addtogroup GT98xx_DRV
 * @{
 */

/**
 * @addtogroup I2C_DRV
 * @{
 */

/**
 * @addtogroup I2C_DRV_Private_Macros I2C Drivers Private Macros
 * @{
 */

/**
 * @def IS_DRV_I2C_MODE
 * @brief Check if __VALUE__ is i2c mode
 */
#define IS_DRV_I2C_MODE(__VALUE__)              (((__VALUE__) == DRV_I2C_MODE_SLAVE) || \
                                                 ((__VALUE__) == DRV_I2C_MODE_MASTER))

/**
 * @def IS_DRV_I2C_TRANSDIRECTION
 * @brief Check if __VALUE__ is i2c transmit direction
 */
#define IS_DRV_I2C_TRANSDIRECTION(__VALUE__)    (((__VALUE__) == DRV_I2C_MST_RX_SLV_TX) || \
                                                 ((__VALUE__) == DRV_I2C_MST_TX_SLV_RX))

/**
 * @def IS_DRV_I2C_ADDRSIZE
 * @brief Check if __VALUE__ is i2c address size
 */
#define IS_DRV_I2C_ADDRSIZE(__VALUE__)          (((__VALUE__) == DRV_I2C_ADDRESS_7BIT) || \
                                                 ((__VALUE__) == DRV_I2C_ADDRESS_10BIT))

/**
 * @def IS_DRV_I2C_TYPE_ACKNOWLEDGE
 * @brief Check if __VALUE__ is i2c ack value
 */
#define IS_DRV_I2C_TYPE_ACKNOWLEDGE(__VALUE__)  (((__VALUE__) == DRV_I2C_CMD_ACK) || \
                                                 ((__VALUE__) == DRV_I2C_CMD_NACK))

/**
 * @def IS_DRV_I2C_SPEED_MODE
 * @brief Check if __VALUE__ is i2c speed mode
 */
#define IS_DRV_I2C_SPEED_MODE(__VALUE__)        (((__VALUE__) == DRV_I2C_BUSSPEED_STANDARD) || \
                                                 ((__VALUE__) == DRV_I2C_BUSSPEED_FAST) || \
                                                 ((__VALUE__) == DRV_I2C_BUSSPEED_FASTPLUS))

/** @} I2C_DRV_Private_Macros */

/**
 * @addtogroup I2C_DRV_Exported_Functions
 * @{
 */

/**
 * @fn ErrorStatus DrvI2cDeInit(I2cTypedef* i2c_instance)
 * @brief De-initialize I2C registers
 * 
 * @param[in] i2c_instance I2C instance
 * @return An ErrorStatus enumeration value
 * @retval kSuccess: I2C registers are de-initialized
 * @retval kError: I2C registers are not de-initialized
 */
ErrorStatus DrvI2cDeInit(I2cTypedef* i2c_instance) {
  ErrorStatus status = kSuccess;
  /* Check the I2C Instance i2c_instance */
  assert_param(IS_I2C_ALL_INSTANCE(i2c_instance));
  if (I2C1 == i2c_instance) {
    CLEAR_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C1);
    SET_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C1);
  } else if (I2C2 == i2c_instance) {
    CLEAR_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C2);
    SET_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C2);
  } else if (I2C3 == i2c_instance) {
    CLEAR_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C3);
    SET_BIT(RST_CTL_REG->MCU_BLK_RST, MCU_BLK_RST_I2C3);
  } else {
    status = kError;
  }
  return status;
}

/**
 * @fn ErrorStatus DrvI2cInit(I2cTypedef* i2c_instance, DrvI2cInitTypedef* i2c_init_struct)
 * @brief Initialize I2C registers according to the specified parameters in @ref DrvI2cInitTypedef
 * 
 * @param[in] i2c_instance I2C instance
 * @param[in] i2c_init_struct pointer to a @ref DrvI2cInitTypedef structure that contians the
 *                            configuration information for the specified I2C peripheral
 * @return An ErrorStatus enumeration value
 * @retval kSuccess: I2C registers are de-initialized
 * @retval kError: I2C registers are not de-initialized
 */
ErrorStatus DrvI2cInit(I2cTypedef* i2c_instance, DrvI2cInitTypedef* i2c_init_struct) {
  ErrorStatus status = kSuccess;
  /* Check if i2c_instance is an I2C instance */
  assert_param(IS_I2C_ALL_INSTANCE(i2c_instance));
  if (I2C1 == i2c_instance) {
    /* Check the parameters */
    assert_param(IS_DRV_I2C_MODE(i2c_init_struct->mode));
    assert_param(IS_DRV_I2C_ADDRSIZE(i2c_init_struct->addr_mode));
    assert_param(IS_DRV_I2C_TRANSDIRECTION(i2c_init_struct->trans_direction));
    assert_param(IS_DRV_I2C_TYPE_ACKNOWLEDGE(i2c_init_struct->type_acknowledge));
    assert_param(IS_DRV_I2C_SPEED_MODE(i2c_init_struct->speed_mode));

    DrvI2cSetMode(i2c_instance, i2c_init_struct->mode);
    DrvI2cEnable(i2c_instance);
    DrvI2cSetBusSpeedMode(i2c_instance, i2c_init_struct->speed_mode);
    DrvI2cSetTransDirection(i2c_instance, i2c_init_struct->trans_direction);
    DrvI2cAcknowledgeNextData(i2c_instance, i2c_init_struct->type_acknowledge);
    DrvI2cSetAddrMode(i2c_instance, i2c_init_struct->addr_mode);
    DrvI2cSetSlaveAddr(i2c_instance, i2c_init_struct->own_address);

    return status;
  } else if (I2C2 == i2c_instance) {
    /* Check the parameters */
    assert_param(IS_DRV_I2C_MODE(i2c_init_struct->mode));
    assert_param(IS_DRV_I2C_ADDRSIZE(i2c_init_struct->addr_mode));
    assert_param(IS_DRV_I2C_TRANSDIRECTION(i2c_init_struct->trans_direction));
    assert_param(IS_DRV_I2C_TYPE_ACKNOWLEDGE(i2c_init_struct->type_acknowledge));
    assert_param(IS_DRV_I2C_SPEED_MODE(i2c_init_struct->speed_mode));

    DrvI2cSetMode(i2c_instance, i2c_init_struct->mode);
    DrvI2cEnable(i2c_instance);
    DrvI2cSetBusSpeedMode(i2c_instance, i2c_init_struct->speed_mode);
    DrvI2cSetTransDirection(i2c_instance, i2c_init_struct->trans_direction);
    DrvI2cAcknowledgeNextData(i2c_instance, i2c_init_struct->type_acknowledge);
    DrvI2cSetAddrMode(i2c_instance, i2c_init_struct->addr_mode);
    DrvI2cSetSlaveAddr(i2c_instance, i2c_init_struct->own_address);
    
    
    return status;
  } else if (I2C3 == i2c_instance) {
    /* Check the parameters */
    assert_param(IS_DRV_I2C_MODE(i2c_init_struct->mode));
    assert_param(IS_DRV_I2C_ADDRSIZE(i2c_init_struct->addr_mode));
    assert_param(IS_DRV_I2C_TRANSDIRECTION(i2c_init_struct->trans_direction));
    assert_param(IS_DRV_I2C_TYPE_ACKNOWLEDGE(i2c_init_struct->type_acknowledge));
    assert_param(IS_DRV_I2C_SPEED_MODE(i2c_init_struct->speed_mode));

    DrvI2cSetMode(i2c_instance, i2c_init_struct->mode);
    DrvI2cEnable(i2c_instance);
    DrvI2cSetBusSpeedMode(i2c_instance, i2c_init_struct->speed_mode);
    DrvI2cSetTransDirection(i2c_instance, i2c_init_struct->trans_direction);
    DrvI2cAcknowledgeNextData(i2c_instance, i2c_init_struct->type_acknowledge);
    DrvI2cSetAddrMode(i2c_instance, i2c_init_struct->addr_mode);
    DrvI2cSetSlaveAddr(i2c_instance, i2c_init_struct->own_address);


    return status;
  } else {
    status = kError;
  }

  return status;
}

/**
 * @fn void DrvI2cStructInit(DrvI2cInitTypedef* i2c_init_struct)
 * @brief Set each @ref DrvI2cInitTypedef field to default value
 * 
 * @param[out] i2c_init_struct pointer to a @ref DrvI2cInitTypedef structure
 *             whose field will be set to default values
 * @return None
 */
void DrvI2cStructInit(DrvI2cInitTypedef* i2c_init_struct) {
  i2c_init_struct->mode                 = DRV_I2C_MODE_MASTER;
  i2c_init_struct->own_address          = 0x00000000;
  i2c_init_struct->addr_mode            = DRV_I2C_ADDRESS_7BIT;
  i2c_init_struct->speed_mode           = DRV_I2C_BUSSPEED_STANDARD;
  i2c_init_struct->trans_direction      = DRV_I2C_MST_TX_SLV_RX;
  i2c_init_struct->type_acknowledge     = DRV_I2C_CMD_ACK;
}

/**
 * @fn void DrvI2cSetBusSpeedMode(I2cTypedef* i2c_instance, uint32_t speed_mode)
 * @brief Set i2c speed mode
 * 
 * @param[in] i2c_instance I2C instance
 * @param[in] speed_mode Speed mode
 * @return None
 */
void DrvI2cSetBusSpeedMode(I2cTypedef* i2c_instance, uint32_t speed_mode)
{
  switch (speed_mode) {
    case DRV_I2C_BUSSPEED_STANDARD: {
      DrvI2cSetSclRatioLow(i2c_instance);
      DrvI2cSetSclHighPeriod(i2c_instance, 0x10);
      DrvI2cSetDataHoldTime(i2c_instance, 0x05);
      DrvI2cSetDataSetupTime(i2c_instance, 0x05);
      DrvI2cSetSpikesPulseWidth(i2c_instance, 0x04);
      break;
    }
    case DRV_I2C_BUSSPEED_FAST: {
      DrvI2cSetSclRatioLow(i2c_instance);
      DrvI2cSetSclHighPeriod(i2c_instance, 0x17);
      DrvI2cSetDataHoldTime(i2c_instance, 0x06);
      DrvI2cSetDataSetupTime(i2c_instance, 0x00);
      DrvI2cSetSpikesPulseWidth(i2c_instance, 0x02);
      break;
    }
    case DRV_I2C_BUSSPEED_FASTPLUS: {
      DrvI2cSetSclRatioLow(i2c_instance);
      DrvI2cSetSclHighPeriod(i2c_instance, 0x17);
      DrvI2cSetDataHoldTime(i2c_instance, 0x06);
      DrvI2cSetDataSetupTime(i2c_instance, 0x00);
      DrvI2cSetSpikesPulseWidth(i2c_instance, 0x02);
      break;
    }
    default: {
      assert_param(IS_DRV_I2C_SPEED_MODE(speed_mode));
    }
  }
}

/** @} I2C_DRV_Exported_Functions */
/** @} I2C_DRV */
/** @} GT98xx_DRV */
